*! opencagegeoi version 1.0 (16/03/2016)
*! Lars Zeigermannn
*  opencagegeoi is a (simplified) immediate version of opencagegeo
*  It reuses a code segment from the libjson help file written by Erik Lindsley

capture program drop opencagegeoi
program opencagegeoi, rclass
        version 12.1
		
		cap which libjson.mlib
        if _rc == 111 {
				di as err "Libjson.mlib not found, please ssc install libjson"
				assert 1 == 2
		}

        if "`0'" == "" { 
                di as err "Please enter location address" 
                exit 198 
        }
		
		if "$mykey" == "" {
				di as err "Define global macro mykey containing your OpenCage Data API key"
				exit 198
		}
		
		if "$language" == "" {
				local language = "en"
		}
		else {
				local language = "$language"
		}
 
		local work = "`0'"
		
		* Change some common address formats causing errors
		local work = lower("`work'")
		local work = subinstr("`work'","&","%26",.)
		local work = subinstr("`work'","#","",.)
		local work = subinstr("`work'"," 01st"," 1st",.)
		local work = subinstr("`work'"," 02nd"," 2nd",.)
		local work = subinstr("`work'"," 03rd"," 3rd",.)
		local work = subinstr("`work'"," 04th"," 4th",.)
		local work = subinstr("`work'"," 05th"," 5th",.)
		local work = subinstr("`work'"," 06th"," 6th",.)
		local work = subinstr("`work'"," 07th"," 7th",.)
		local work = subinstr("`work'"," 08th"," 8th",.)
		local work = subinstr("`work'"," 09th"," 9th",.)
		local work = subinstr("`work'",`"""'," ",.)

		* Remove multiple blanks
		local work = itrim("`work'")
		
		* Remove blanks after commas
		local work = subinstr(strtrim("`work'"), ", ", ",",.)		

		* Remove leading and trailing blanks and replace interior blanks with +
		local work = subinstr(strtrim("`work'"), " ", "+",.)
		
		* Check work for special characters (Stata 13 or older) or encode (if Stata 14 or newer)
		if c(stata_version) >= 14 {
			local work = ustrto("`work'", "ascii", 4)
			local work = subinstr("`work'","\","%",.)
		}
		else {
			foreach num of numlist 1/31 127/255 {
			cap assert index("`work'",char(`num')) == 0
				if _rc != 0 {
					di as err "Location address may not contain special characters"
					exit 499
				}
			}
		}

		local url "http://api.opencagedata.com/geocode/v1/json?q=`work'&key=$mykey&no_annotations=1&limit=1&language=`language'"
		
		cap mata: get_OpenCageData("`url'")

		if "`status'" != "OK" {
			di in red "Server refused to send file: Check key, internet connection and query limit"
			exit 199
		}
		
		if c(stata_version) >= 14 {
			local formatted = ustrunescape("`formatted'")
		}
		
		* Store results in r()
		return local confidence `conf'
		return local longitude `lon'
		return local latitude `lat'
		return local formatted_address `formatted'
		return local input_address `0'
		

		di "*********************************"
		di "*** OpenCage Geocoder Results ***"
		di "*********************************"
		di "Formatted address: `formatted'"
		di "Latitude: `lat'"
		di "Longitude: `lon'"
	
end

version 12.1
mata:
void get_OpenCageData(url) {

		selectors="results:1:formatted","results:1:geometry:lat","results:1:geometry:lng","results:1:confidence"
		
		pointer (class libjson scalar) scalar root
		root = libjson::webcall(url,"")
		if (root) {
				string rowvector res
				res = J(1,4,"")
				for (c=1; c<= 4; c++) {       
						res[c] = root->getString( libjson::parseSelector(selectors[c]) ,"")
				}
				
				st_local("status","OK")
				st_local("formatted", res[1,1])
				st_local("lat", res[1,2])
				st_local("lon", res[1,3])
				st_local("conf", res[1,4])
		} 
}
end	

exit
